import libvirt
import time
from libvirtex import open_libvirt, virDomainEx
from devices import HDDFileDevice, ETHDevice
from storage import get_all_vms
from utils import tmap
from network import is_host_alive
from cmd_executor import SSHCMDExecutor

def mkvm_nosql_root(conn):
    hw = '00:44:01:61:76:fB'
    ip = '192.168.122.6'

    ubuntu_img_path = '/home/koder/vm_images/ubuntu-kvm-test.qcow2'
    vm = virDomainEx.construct(conn,
                               True,
                               'nosql-root',
                               1024 * 1024,
                               1,
                               HDDFileDevice(ubuntu_img_path, 'qcow2'), 
                               ETHDevice(hw, "vnet7", ip = ip))
    vm.save_network()

def mkvm_nosql(conn, num):
    hw_list = ['00:44:01:61:76:f7',
               '00:44:01:61:76:f8',
               '00:44:01:61:76:f9',
               '00:44:01:61:76:fA']
    
    ip_list = ['192.168.122.2',
               '192.168.122.3',
               '192.168.122.4',
               '192.168.122.5']

    for pos in range(num):    

        name = 'nosql-{0}'.format(pos)
        ubuntu_img_path = '/home/koder/vm_images/ubuntu-kvm-diff{0}.qcow2'\
                                    .format(pos)
        vm = virDomainEx.construct(conn,
                                   True,
                                   name,
                                   1024 * 1024,
                                   1,
                                   HDDFileDevice(ubuntu_img_path, 'qcow2'), 
                                   ETHDevice(hw_list[pos], "vnet7",
                                             ip = ip_list[pos]))
        vm.save_network()

expect_script = r'''
spawn ssh {0}@{1}
expect {{
    "password:" {{ send "{2}\n" }}
    "connecting (yes/no)?" {{ send "yes\n"; exp_continue}}
}}
interact
'''

def mkvm_debian(conn):
    img_path = '/home/koder/vm_images/debian_squeeze_amd64_standard.qcow2'
    name = 'debian'
    
    mac = conn.findFreeMac(name)
    vm = virDomainEx.construct(conn, name, 512, 1,
            HDDFileDevice(img_path, 'qcow2'), 
            ETHDevice(mac, "vnet7"))
    
    with vm.create(conn):
        vm.set_ssh_credentials('root', 'root')
        vm.set_rpyc_pem_file('/home/koder/cert.pem')
        vm.wait_ssh_ready()
        

def get_vm_ip(conn, vmname):
    vm = conn.lookupByName(vmname)
    
    return [eth.ip for eth in vm.eths(with_ip=True)]


def split_login(lline, user='ubuntu', passwd='ubuntu'):
    if '@' in lline:
        user_pass, host = lline.split('@')
        user, passwd = user_pass.split(':')
    else:
        host = lline
    return user, passwd, host

if __name__ == "__main__":
    import sys
    import optparse
    import os
    
    parser = optparse.OptionParser()

    parser.add_option('--vm-ip', dest='get_ip', action='store_true',
                      default = False)
    parser.add_option('--conn', dest='conn_str',
                      default = "qemu:///session")
    parser.add_option('--login', dest='login', action='store_true',
                      default = False)
    parser.add_option('--start-set', dest='start_set', action='store_true',
                      default = False)
    parser.add_option('--stop-set', dest='stop_set', action='store_true',
                      default = False)
    parser.add_option('--set-state', dest='set_state', action='store_true',
                      default = False)

    opts, files = parser.parse_args(sys.argv)
        
    if opts.get_ip:
        conn = open_libvirt(opts.conn_str)
        ips = get_vm_ip(conn, files[1])
        print ips[0]
    elif opts.login:
        
        user, passwd, vm_name = split_login(files[1])
        conn = open_libvirt(opts.conn_str)
        ip = get_vm_ip(conn, vm_name)[0]
        
        if ip is None:
            print "Can't found any sutable ip for domain {0}".format(vm_name)
        else:
            with open('/tmp/login.exp', 'w') as fd:
                fd.write(expect_script.format(user, ip, passwd))

            os.system("expect /tmp/login.exp")
    elif opts.start_set:
        if len(files) == 1:
            print >> sys.stderr, "Cluster name should be given"
        elif files[1] == 'nosql':
            mkvm_nosql(open_libvirt(opts.conn_str), 4)
        elif files[1] == 'nosql-root':
            mkvm_nosql_root(open_libvirt(opts.conn_str))
    elif opts.set_state:
        if len(files) == 1:
            print >> sys.stderr, "vm name template should be given"
        
        conn = open_libvirt(opts.conn_str)
        all_ips = {}
        is_alive = {}
        all_names = []

        for templ in files[1:]:
            for vm_name, ips in get_all_vms(templ):
                ip = ips.values()[0]
                all_names.append(vm_name)
                try:
                    vm = conn.lookupByName(vm_name)
                except libvirt.libvirtError:
                    is_alive[vm_name] = False, None
                else:
                    all_ips[ip] = vm_name
        
        for _, res_ip, res in tmap(is_host_alive, all_ips.keys()):
            is_alive[all_ips[res_ip]] = res, res_ip
        
        for vm_name in all_names:
            ok, ip = is_alive[vm_name]
            print vm_name.center(15),
            print "WORKS" if ok else "DOWN",
            print ip.center(15) if ip else ''
            
    elif opts.stop_set:
        if len(files) == 1:
            print >> sys.stderr, "vm name template should be given"
        
        conn = open_libvirt(opts.conn_str)

        def shutdown_vm(val, max_time = 30):
            stime = time.time()
            conn, user, passwd, ip, name = val
            res = False

            if is_host_alive(ip):
                print "Power off {0}:{1}".format(name, ip)
                cmd = SSHCMDExecutor(ip, username, passwd)
                cmd.exec_simple(*('sudo poweroff'.split()))
            
            print "wait while {0}:{1} stop pinging".format(name, ip)
            
            while time.time() - stime < max_time:
                if not is_host_alive(ip):
                    res = True
                    break

            if time.time() - stime > max_time and not res:
                print "Timeouted {0}:{1}. Destory it".format(name, ip)
            else:
                print "{0}:{1} don't responce on ping anymore. Destory it".format(name, ip)

            try:
                vm = conn.lookupByName(name)
            except libvirt.libvirtError:
                pass
            else:
                vm.destroy()
                
            return True
            
        params = []
        
        for templ in files[1:]:
            username, passwd, vm_templ = split_login(templ)
            for vm_name, ips in get_all_vms(vm_templ):
                params.append([conn, username, passwd,
                               ips.values()[0], vm_name])
            
        for ok, param, res in tmap(shutdown_vm, params):
            print param[-1], res
    else:
        print "Unknown options!"
        

        






